import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

typedef ClickableBuilder = Widget Function(
    BuildContext context, ClickableBuilderInfo info);

class ClickableBuilderInfo {
  ClickableBuilderInfo({
    required this.isHighlight,
    required this.isHover,
  });

  final bool isHighlight;
  final bool isHover;
}

class ClickableWidget extends StatefulWidget {
  ClickableWidget({
    required this.builder,
    Key? key,
    this.onTap,
    this.onTapDown,
    this.onDoubleTap,
  }) : super(key: key);

  final ClickableBuilder builder;

  final VoidCallback? onTap;
  final VoidCallback? onTapDown;
  final VoidCallback? onDoubleTap;

  @override
  State<StatefulWidget> createState() {
    return _ClickableWidgetState();
  }
}

class _ClickableWidgetState extends State<ClickableWidget> {
  bool _isTouchDown = false;
  bool _isHighlighting = false;
  bool _isHighlighted = false;
  bool _isHover = false;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    GestureTapCallback? onTapCallback;
    if (widget.onTap != null) {
      onTapCallback = () {
        widget.onTap!();
      };
    }

    GestureTapCallback? onDoubleTapCallback;
    if (widget.onDoubleTap != null) {
      onDoubleTapCallback = () {
        widget.onDoubleTap!();
      };
    }

    Widget child = GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: onTapCallback,
      onDoubleTap: onDoubleTapCallback,
      onTapDown: (details) {
        highlight();
        if (widget.onTapDown != null) {
          widget.onTapDown!();
        }
      },
      onTapUp: (details) {
        cancelHighlight();
      },
      onTapCancel: cancelHighlight,
      child: widget.builder(
        context,
        ClickableBuilderInfo(
          isHighlight: _isHighlighted,
          isHover: _isHover,
        ),
      ),
    );

    return MouseRegion(
      onEnter: (event) {
        setState(() {
          _isHover = true;
        });
      },
      onExit: (event) {
        setState(() {
          _isHover = false;
        });
      },
      cursor: SystemMouseCursors.click,
      child: child,
    );
  }

  void highlight() {
    _isTouchDown = true;

    setState(() {
      _isHighlighted = true;
    });
  }

  void cancelHighlight() {
    if (_isTouchDown) {
      _isTouchDown = false;
      if (!_isHighlighting) {
        _isHighlighting = true;

        Future.delayed(
          Duration(milliseconds: 200),
          () {
            if (mounted) {
              _isHighlighting = false;
              setState(() {
                _isHighlighted = false;
              });
            }
          },
        );
      }
    }
  }
}
